maniaplanetfandomcom-20200214-history
GBX
General information TrackMania gamebox files (*.gbx) are generic container files that can contain everything from configuration to textures to track definitions. They consist of a header, a reference table and the body. In old versions of TrackMania they used to be text files - nowadays they are binary files. Integers are stored in little endian order. The file body is often compressed (using LZO). __TOC__ Engines, classes, chunks A .gbx file more specifically stores the serialization of one or more class instances. There is one main instance, and optionally a number of auxiliary instances. The serializable classes are organized into 16 engines. Each class is also subdivided into chunks. A class is then not serialized in one go, but rather as a series of chunks. This allows Nadeo to easily extend classes in new TrackMania versions: instead of having to define a new class they can simply add more chunks to an existing one, and have older versions ignore these new chunk types. The data in a gbx file follows the pattern . A chunk ID is a 32-bit number that identifies the engine, the class, and the chunk in that class. If you for example see the bytes 07 30 04 03 in the file, that would correspond to the integer 0x03043007, and be interpreted as follows: engine class chunk 03 043 007 All engines and classes are named; in this case, engine 3 is the Game engine, and class 043 in that engine is CGameCtnChallenge. Chunks do not have names. Apart from chunk ID's there are also class ID's, which are just like chunk ID's except the chunk index part is ignored (and 0). For a complete overview of engines and classes, see Class ID's. Header The header contains things like compression information and the class ID of the main class instance. The current version of the header also provides a few chunks of the main class that serve as meta information (e.g. the thumbnail of a challenge). * byte3 magic: "GBX" * uint16 version: currently 6 * if version >= 3: ** byte format: 'B' or 'T': Binary or Text (always B for version 6 gbx files) ** byte compression: 'U' or 'C': Uncompressed or Compressed reference table (unused, always U) ** byte compression: 'U' or 'C': Uncompressed or Compressed body (typically C for binary files) ** if version >= 4: *** byte unknown: 'R' or 'E': unknown purpose (typically R for binary files) ** uint32 classID (class ID of main class instance) ** if version >= 6: *** uint32 userDataSize *** byteuserDataSize: **** uint32 numHeaderChunks **** HeaderEntrynumHeaderChunks ***** uint32 chunkID ***** uint32 chunkSize (may have bit 31 set. This indicates a "heavy" header chunk which is skipped while scanning gbx files on game startup) **** concatenated data of header chunks ** uint32 numNodes: the total number of class instances related to this gbx file. This includes the main instance, any local auxiliary instances, and any referenced external nodes/files. An internal list will be allocated with this number of entries; the main instance is at index 0. Reference Table * uint32 numExternalNodes: the number of external nodes and files that this .gbx references. These come from other files located in the .gbx's .pak file. The references to these will be placed in the same list as the local nodes (see above). Both raw files (e.g. textures) and .gbx main instances can be referenced. * if numExternalNodes > 0: ** uint32 ancestorLevel: how many folder levels to go up in the .pak folder hierarchy to reach the base folder from which files will be referenced. ** uint32 numSubFolders ** Folder foldersnumSubFolders *** string name *** uint32 numSubFolders *** Folder foldersnumSubFolders ** ExternalNode externalsnumExternalNodes *** uint32 flags *** if (flags & 4) 0: **** string fileName *** else: **** uint32 resourceIndex *** uint32 nodeIndex (the index in the local node list where this external reference will be stored) *** if version >= 5: (header version) **** bool useFile (0 or 1, whether to use the file itself or the node that was loaded from the file) *** if (flags & 4) 0: **** uint32 folderIndex: the depth-first index of the folder which the file is in. 0 means the base folder itself. Body * if body is compressed: ** uint32 uncompressedSize ** uint32 compressedSize ** byte datacompressedSize (compressed with regular LZO) * else: ** byte data[] Reading the body The file body contains further chunks of the main class instance, and may also contain auxiliary class instances. Reading the body is started by creating an in-memory instance of the class corresponding to the main class ID (instances are called nodes internally), and calling ReadNode on it: ReadNode() { while(true) { chunkID = ReadUInt32(); if(chunkID 0xFACADE01) return; chunkFlags = GetChunkFlags(chunkID); if(chunkFlags & 0x10) { skip = ReadUInt32(); chunkDataSize = ReadUInt32(); } ReadChunk(chunkID); } } GetChunkFlags() doesn't read anything from the file; it provides loading flags for the specified chunk ID. The only important flag is whether or not the chunk is "skippable". If it is, the chunk ID is followed by an uint32 0x50494B53 ("SKIP", shows up as "PIKS" in the file due to little endian ordering) and an uint32 specifying the size of the chunk data. This allows older versions of TrackMania that don't know how to parse this chunk ID to skip over the chunk data and go to the next chunk. If the chunk is not skippable, the chunk data follows immediately after the chunk ID. A dummy chunk ID of 0xFACADE01 signifies the end of the chunk list for the current class. Chunk data is not self-describing; the program itself has to know how to read each one. In fact, if your program doesn't know a specific chunk ID and the chunk is not skippable, you can't even tell how long the chunk is. We will first describe a number of "primitives" that are used when reading and writing chunks. Then we will describe the contents of a number of common chunks. Primitives * bool: 32-bit little-endian integer that can be 0 or 1. * byte, uint16, int32, uint32, uint64, uint128, float: regular little endian encoding. * vec2D: ** float x ** float y * vec3D: ** float x ** float y ** float z * color: ** float r ** float g ** float b * string: ** uint32 length ** byte charslength (UTF8, older files sometimes with BOM, not zero-terminated) * lookbackstring: a form of compression which allows to avoid repeating the same string multiple times. Everytime a new string is encountered, it is added to a string list, and from then on this list entry is referenced instead of repeating the string another time. ** if this is the first lookback string encountered: *** uint32 version (currently 3) ** uint32 index: bit 31 and 30 define the string type. If both bits are 0, the index is a number. The actual index is bits 0-29. If it is 0, a new string follows (and will be added to the string list). If it is greater than one, use the string at stringlist - 1. A value of -1 means there is no data provided (unassigned). ** if (index & 0xC0000000) != 0 and (index & 0x3FFFFFFF) 0: *** string newString. Append to the string list. Note: the lookback string state is reset after each header chunk. The string list is cleared completely, and the next lookback string will again trigger the version number. If index represents a number (bits 30 and 31 not set), it describes the position inside a global string table. In most cases it concerns the ID of a collection. The correspondences used up to now are: 11 = 'Valley', 12 = 'Canyon', 17 = 'TMCommon', 202 = 'Storm', 299 = 'SMCommon', 10003 = 'Common'. * fileref: path to an external file, e.g. a skin. ** byte version (currently 3) ** if version >= 3: *** byte32 (checksum) ** string filePath (skin: if version < 2 relative to Skins folder else relative to user folder) ** if filePath.length > 0 && version >= 1: *** string locatorUrl * meta: contains meta information like the track environment, time of day, and author. ** lookbackstring field1 ** lookbackstring field2 ** lookbackstring author * noderef: a reference to an auxiliary class instance. ** uint32 index. if this is -1, the node reference is empty (null). ** if the index is >= 0 and the node at the index has not been read yet: *** uint32 classID: instantiate a new node for this class ID and store it in the node list at the specified index. *** ReadNode() Note: In case of a text format gbx file (marked by a 'T' in the header) all numbers and strings are stored as one line of ASCII text in each case. Every line ends with a carriage return-linefeed () combination (0x0D and 0x0A). A single is part of a string. Class descriptions CGameCtnChallenge (03 043 000) 03043002 "TmDesc" byte version if version < 3: meta (trackUID, environment, mapAuthor) string trackName bool 0 if version >= 1: uint32 bronzeTime (ms) uint32 silverTime (ms) uint32 goldTime (ms) uint32 authorTime (ms) if version 2: byte if version >= 4: uint32 copperPrice if version >= 5: bool multilap if version 6: bool if version >= 7: uint32 trackType (0: Race, 1: Platform, 2: Puzzle, 3: Crazy, 4: Shortcut, 5: Stunts, 6: Script) if version >= 9: uint32 0 if version >= 10: uint32 authorScore if version >= 11: uint32 editorMode (bit 0: advanced/simple editor, bit 1: has ghost blocks) if version >= 12: bool 0 if version >= 13: uint32 nbCheckpoints uint32 nbLaps 03043003 "Common" byte version meta (trackUID, environment, mapAuthor) string trackName byte kind (0: (internal)EndMarker, 1: (old)Campaign, 2: (old)Puzzle, 3: (old)Retro, 4: (old)TimeAttack, 5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo) if version >= 1: bool locked (used by VirtualSkipper to lock the map parameter) string password (weak xor encryption, no longer used in newer track files; see 03043029) if version >= 2: meta decoration (timeOfDay, environment, envirAuthor) (decoration envir can be different than collection envir) if version >= 3: vec2D mapOrigin if version >= 4: vec2D mapTarget if version >= 5: uint128 if version >= 6: string mapType string mapStyle if version <= 8: bool if version >= 8: uint64 lightmapCacheUID if version >= 9: byte lightmapVersion if version >= 11: lookbackstring titleUID 03043004 "Version" uint32 version 03043005 "Community" string xml The XML block contains everything the 003 header chunk does, except for the password. Unlike the 003 chunk, however, it also contains the list of dependencies for the track (images, mods, music, etc.), as well as the version number of the software that created the track, the actual number of laps, and an optional Mod name. 03043007 "Thumbnail" uint32 version if version != 0: uint32 thumbSize "" byte thumbthumbSize "" "" string comments "" 03043008 "Author" uint32 version uint32 authorVersion string authorLogin string authorNick string authorZone string authorExtraInfo 0304300D meta (vehicle, collection, author) 03043011 noderef collectorList noderef challengeParameters uint32 kind (0: (internal)EndMarker, 1: (old)Campaign, 2: (old)Puzzle, 3: (old)Retro, 4: (old)TimeAttack, 5: (old)Rounds, 6: InProgress, 7: Campaign, 8: Multi, 9: Solo, 10: Site, 11: SoloNadeo, 12: MultiNadeo) 03043014 (skippable) uint32 string password (old style password with weak xor encryption. this chunk is no longer used in newer track files, see 03043029) 03043017 (skippable) uint32 numCheckpoints CheckpointnumCheckpoints Checkpoint: uint32 uint32 uint32 03043018 (skippable) uint32 uint32 numLaps 03043019 (skippable) fileref modPackDesc 0304301C (skippable) uint32 playMode (0: Race, 1: Platform, 2: Puzzle, 3: Crazy, 4: Shortcut, 5: Stunts) 0304301F meta (trackUID, environment, mapAuthor) string trackName meta decoration (timeOfDay, environment, envirAuthor) uint32 sizeX uint32 sizeY uint32 sizeZ uint32 needUnlock uint32 flagsAre32Bit uint32 numBlocks for each block: lookbackstring blockName byte rotation (0/1/2/3) byte x byte y byte z uint16/uint32 flags if (flags 0xFFFFFFFF) continue (read the next block) if (flags & 0x8000) != 0: custom block lookbackstring author noderef skin if (flags & 0x100000) noderef blockparameters Note: blocks with flags 0xFFFFFFFF should be skipped, they aren't counted in the numBlocks. Note: It is possible that additional blocks with flags 0xFFFFFFFF (Unassigned) follow after all other blocks. 03043021 noderef clipIntro noderef clipGroupInGame noderef clipGroupEndRace 03043022 uint32 03043024 fileref customMusicPackDesc 03043025 vec2D mapCoordOrigin vec2D mapCoordTarget 03043026 noderef clipGlobal 03043027 uint32 provided if provided != 0: byte vec3D x 3 vec3D float float float 03043028 ReadChunk(0x03043027) string comments 03043029 (skippable) uint128 passwordHash (salted MD5) uint32 CRC32("0x" + hex(passwordHash) + "???" + trackUID) 0304302A uint32 0304303D (skippable) bool unknown uint32 version if version >= 2: if version >= 4: uint32 size byte riffsize // Avg lightmap webp file uint32 size byte jfifsize // Intens/Avg lightmap jpeg file if version 3: uint32 size byte jfifsize // Intens lightmap jpeg file if size != 0: uint32 uncompressedSize uint32 compressedSize byte datacompressedSize CGameCtnCollectorList (03 01B 000) 0301B000 uint32 num Item itemsnum meta uint32 CGameCtnChallengeParameters (03 05B 000) 0305B000 (all fields are ignored) uint32 uint32 uint32 uint32 uint32 uint32 uint32 uint32 0305B001 string tip string tip string tip string tip 0305B002 (all fields are ignored) uint32 uint32 uint32 float float float uint32 uint32 uint32 uint32 uint32 uint32 uint32 uint32 uint32 uint32 0305B003 (all fields are ignored) uint32 float uint32 uint32 uint32 uint32 0305B004 uint32 bronzeTime (ms) uint32 silverTime (ms) uint32 goldTime (ms) uint32 authorTime (ms) uint32 ignored 0305B005 uint32 x 3 (ignored) 0305B006 uint32 num uint32 itemscount (ignored) 0305B008 uint32 timeLimit (ms) uint32 authorScore (ms) 0305B00A (skippable) uint32 (0?) uint32 bronzeTime (ms) uint32 silverTime (ms) uint32 goldTime (ms) uint32 authorTime (ms) uint32 timeLimit (ms) uint32 authorScore (ms) 0305B00D uint32 (-1?) 0305B00E (skippable) uint32 uint32 uint32 CGameCtnBlockSkin (03 059 000) 03059000 string text string ignored 03059001 string text fileref packDesc 03059002 string text fileref packDesc fileref parentPackDesc CGameWaypointSpecialProperty (0313B000) 0313B000 uint32 version if version 1: uint32 spawn uint32 order if version 2: string tag uint32 order CGameCtnReplayRecord (03 093 000) 03093000 "Version" uint32 version if version >= 2: meta (trackUID, environment, author) uint32 time (ms) string nickName if version >= 6: string driverLogin if version >= 8: byte 1 lookbackstring titleUID 03093001 "Community" string xml The XML block contains the UID and replay ("best") time like in the header. It also contains the version number of the software that created the replay; optionally the respawns count (can be -1 or larger), the Stunts score, and a validable flag; and in recent versions occasionally two checkpoints fields. 03093002 "Author" (header) uint32 version uint32 authorVersion string authorLogin string authorNick string authorZone string authorExtraInfo 03093002 (body) uint32 size byte GBXsize, the track the replay was recorded on 03093007 (skippable) uint32 03093014 uint32 ignored (0xA) uint32 numGhosts noderef ghostsnumGhosts uint32 ignored uint32 num uint64numExtras 03093015 noderef CGameGhost (03 03F 005) 0303F005 uint32 uncompressedSize uint32 compressedSize byte compressedDatacompressedSize: (compressed with zlib deflate) uint32 classID bool bSkipList2 uint32 uint32 samplePeriod uint32 uint32 size byte sampleDatasize (samples of position, rotation, speed... of the car during the race) uint32 numSamples if numSamples > 0: uint32 firstSampleOffset if numSamples > 1: uint32 sizePerSample if sizePerSample -1: uint32 sampleSizes- 1 if bSkipList2 0: uint32 num int32 sampleTimesnum 0303F006 uint32 IsReplaying ReadChunk(0x0303F005) A sample record looks as follows: vec3D position uint16 angle (0..0xFFFF -> 0..pi) int16 axisHeading (-0x8000..0x7FFF -> -pi..pi) int16 axisPitch (-0x8000..0x7FFF -> -pi/2..pi/2) int16 speed (-> exp(speed/1000); 0x8000 means 0) int8 velocityHeading (-0x80..0x7F -> -pi..pi) int8 velocityPitch (-0x80..0x7F -> -pi/2..pi/2) ... (more unknown data) The rotation of the car is calculated as a quaternion. * The real part of the quaternion is calculated as cos(angle) which corresponds to a rotation of 2*angle around the rotation axis. * The imaginary part of the quaternion (the rotation axis) is calculated as the vector (sin(angle)*cos(axisPitch)*cos(axisHeading), sin(angle)*cos(axisPitch)*sin(axisHeading), sin(angle)*sin(axisPitch)). You can convert this quaternion to a transform matrix. The velocity vector (direction and speed of movement) is calculated in a similar way: (speed*cos(velocityPitch)*cos(velocityHeading), speed*cos(velocityPitch)*sin(velocityHeading), speed*sin(velocityPitch)). CGameCtnGhost (03 092 000) CGameCtnGhost is a subclass of CGameGhost. If you encounter an unknown chunk ID while reading a CGameCtnGhost instance, delegate it to CGameGhost. 03092005 (skippable) uint32 raceTime 03092008 (skippable) uint32 numRespawns 03092009 (skippable) color lightTrailColor 0309200A (skippable) uint32 stuntsScore 0309200B (skippable) uint32 num uint64num 0309200C uint32 ignored 0309200E lookbackstring uid 0309200F string ghostLogin 03092010 lookbackstring 03092012 uint32 ignored uint128 03092013 (skippable) uint32 uint32 03092014 ''' (skippable) uint32 '''03092015 lookbackstring playerMobilId 03092017 (skippable) uint32 num fileref skinPackDescsnum string ghostNickname string ghostAvatarName 03092018 meta 03092019 uint32 eventsDuration uint32 ignored uint32 numControlNames lookbackstring controlNamesnumControlNames uint32 numControlEntries uint32 ControlEntrynumControlEntries uint32 time (ms + 100000) byte controlNameIndex uint32 onoff (1/0) string gameVersion uint32 exeChecksum uint32 osKind uint32 cpuKind string raceSettingsXML uint32 CGameCtnCollector (0301A000) Base class for CGameCtnBlockInfo, CGameCtnMacroBlockInfo, CGameCtnObjectInfo and CGameCtnDecoration. Deprecated. Moved to the new GameData engine (2E) as class CGameCtnCollector (2E001000). 0301A003 "Desc" (header) meta (name, collection, author) lookbackstring version string pagePath (slash-separated folder path where the block appears in the editor) if version = 5 lookbackstring if version >= 4 lookbackstring if version >= 3 uint32 flags uint16 index if version >= 7 string name 0301A004 "Icon" (header) uint16 iconWidth uint16 iconHeight byte iconData4*iconWidth*iconHeight // one RGBA uint32 per pixel 0301A006 (header) uint64 filetime // lightmap cache timestamp 0301A007 bool isInternal uint32 uint32 catalogPosition uint32 uint32 uint32 0301A009 string pagePath (same as in chunk 0301A003) bool hasIconFid if hasIconFid: noderef iconFid lookbackstring 0301A00B meta 301A00C string name 301A00D string description 0301A00E bool iconUseAutoRender uint32 iconQuarterRotationY 0301A00F string defaultSkinName CGameCtnObjectInfo (0301C000) Deprecated. Moved to the new GameData engine (2E) as class CGameItemModel (2E002000). 0301C000 (header) uint32 objectInfoType (0: Undefined, 1: Ornament, 2: PickUp, 3: Character, 4: Vehicle) Note: In class CGameItemModel the enumerators are: 0: Undefined, 1: StaticObject, 2: DynaObject, 3: Character, 4: Vehicle, 5: Spot, 6: Cannon 0301C001 (header) uint32 0301C006 uint32 defaultCamIndex (-1 = none, 0 and above = camera index; used for cars) 0301C008 uint32 numNadeoSkinFids noderef fidsnumNadeoSkinFids (file references) 0301C009 uint32 version = 10 uint32 numCameras noderef camerasnumCameras (references to CGameControlCamera; used for cars) 0301C00A noderef decoratorSolid (CPlugDecoratorSolid) 0301C00B noderef stemMaterial (CPlugMaterial) noderef stemBumpMaterial (CPlugMaterial) 0301C00C noderef raceInterfaceFid 0301C010 noderef bannerProfileFid (file reference to e.g. BannerProfileCanyon.Texture.gbx) 0301C012 vec3D groundPoint float painterGroundMargin float orbitalCenterHeightFromGround float orbitalRadiusBase float orbitalPreviewAngle 301C013 nodref audioEnvironmentInCar (CPlugAudioEnvironment; used for cars) 301C014 noderef baseAttributes (CGameAttributes; unused?) 301C015 uint32 objectInfoType (0: Undefined, 1: Ornament, 2: PickUp, 3: Character, 4: Vehicle) 0301C016 noderef defaultSkinFid 0301C017 uint32 version = 0 bool isFreelyAnchorable 0301C018 int version = 0 bool isUsable 0301C019 int version nodref phyModel // CPlugSurface nodref visModel // CPlugSurface if version >= 1: nodref visModelStatic // CPlugSolid2Model CGameCtnDecoration (03038000) 03038000 "MoodRemaping" byte version string dirName ReadChunk(0x03031000) 03038001 byte version uint32 unknown CGameCtnCollection (03033000) 03033001 "Desc" byte version lookbackstring environment bool if version >= 1: string iconEnv string iconCollection if version >= 2: int32 if version >= 3: lookbackstring terrain if version >= 4: meta (vehicle, collection, author) if version >= 5: string float float float float if version <= 5: float float if version <= 7: float float if version >= 7: string loadscreen if version >= 8: float float float float float float string if version >= 9: string name if version >= 10: bool 03033002 "CollectorFolders" byte version string dirName string dirName string dirName if version 1 || version 2: string dirName if version >= 2: string dirName if version >= 3: string dirName if version >= 4: string dirName 03033003 "MenuIconsFolders" byte version string dirName CGameSkin (03031000) 03031000 "Skin" byte version string dirName if version >= 1: string textureName string sceneId byte number for each number: uint32 classId string name string file if version >= 2: bool mipMap if version >= 4: string dirNameAlt if version >= 5: bool unknown CGamePlayerProfile (0308C000) 0308C000 "NetPlayerProfile" string login string onlineSupportKey CMwNod (01001000) 01001000 "FolderDep" uint32 number for each number: string dirName Historical information While the above description of *.Gbx files is far more complete and precise than before, it is also entirely different from – and more abstract than – the original description, which formed the basis for several of the tools below. That historical description can still be viewed at this revision link. Applications and Libraries that can inspect/modify the file format * GBX Data Fetcher - a PHP module with classes to extract useful data from .Challenge|Map.Gbx files (including the thumbnail image), .Replay.Gbx files and .Pack.Gbx|.pak files, as well as parse their XML blocks. * Extract GBX data - a PHP script to format and print data from all file types supported by the GBX Data Fetcher module. * Tally GBX versions - a PHP script to tally some version data from all .Challenge|Map.Gbx files (including sample challenges in all known versions). * TrackStudio - a Windows TrackMania Forever track editor with 3D interface. * Blockmix tools - Challenge editing tools (Recompressor, ChallengeEdit, GBX-Master, CELightRotate, TmfBlockMixEdition). * TMPakTool - Open and edit .pak files. * TMUnlimiter - Patches the in-game track editor to remove the block placement restrictions. * GBXedit - Command-line based blockmix editor for TM² Stadium maps. * MapEdit - GUI-based blockmix editor for all ManiaPlanet maps. * GbxDump - a Windows tool to dump and analyze the header of all kinds of .Gbx files. * ReplayToChallenge - a Windows tool to extract a Challenge from a .Replay.Gbx file (includes source code). * Easy TM * Trackmania Disassembler - includes a library allowing you to write your own applications that can read the format. This article was mirrored from the old TM Wiki at http://en.tm-wiki.org/wiki/GBX It is the version as of 24 August 2014, at 15:27.